package org.yzhzc.friend.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.yzhzc.common.core.constants.CacheConstants;
import org.yzhzc.common.core.domain.PageQueryDTO;
import org.yzhzc.common.redis.service.RedisService;
import org.yzhzc.friend.domain.message.vo.MessageTextVO;
import org.yzhzc.friend.mapper.message.MessageTextMapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 消息缓存管理器。
 * 负责管理用户消息的缓存操作，包括缓存刷新、缓存查询等。
 */
@Component // 标识该类为 Spring 组件，由 Spring 容器管理
public class MessageCacheManager {

    @Autowired // 自动注入 Redis 服务
    private RedisService redisService;

    @Autowired // 自动注入消息文本数据访问接口
    private MessageTextMapper messageTextMapper;

    /**
     * 获取用户消息列表的长度。
     *
     * @param userId 用户 ID
     * @return 消息列表的长度
     */
    public Long getListSize(Long userId) {
        String userMsgListKey = getUserMsgListKey(userId); // 获取用户消息列表的缓存键
        return redisService.getListSize(userMsgListKey); // 从 Redis 中获取列表长度
    }

    /**
     * 获取用户消息列表的缓存键。
     *
     * @param userId 用户 ID
     * @return 缓存键
     */
    private String getUserMsgListKey(Long userId) {
        return CacheConstants.USER_MESSAGE_LIST + userId; // 拼接缓存键
    }

    /**
     * 获取消息详情的缓存键。
     *
     * @param textId 消息文本 ID
     * @return 缓存键
     */
    private String getMsgDetailKey(Long textId) {
        return CacheConstants.MESSAGE_DETAIL + textId; // 拼接缓存键
    }

    /**
     * 刷新用户消息缓存。
     *
     * @param userId 用户 ID
     */
    public void refreshCache(Long userId) {
        List<MessageTextVO> messageTextVOList = messageTextMapper.selectUserMsgList(userId); // 查询用户消息列表
        if (CollectionUtil.isEmpty(messageTextVOList)) { // 如果消息列表为空
            return;
        }

        // 获取消息文本 ID 列表
        List<Long> textIdList = messageTextVOList.stream().map(MessageTextVO::getTextId).toList();
        String userMsgListKey = getUserMsgListKey(userId); // 获取用户消息列表的缓存键
        redisService.rightPushAll(userMsgListKey, textIdList); // 将消息文本 ID 列表存入 Redis

        // 构建消息详情的缓存数据
        Map<String, MessageTextVO> messageTextVOMap = new HashMap<>();
        for (MessageTextVO messageTextVO : messageTextVOList) {
            messageTextVOMap.put(getMsgDetailKey(messageTextVO.getTextId()), messageTextVO); // 拼接缓存键并存入 Map
        }
        redisService.multiSet(messageTextVOMap); // 批量设置缓存
    }

    /**
     * 获取用户消息列表。
     *
     * @param dto    分页查询条件
     * @param userId 用户 ID
     * @return 用户消息列表
     */
    public List<MessageTextVO> getMsgTextVOList(PageQueryDTO dto, Long userId) {
        int start = (dto.getPageNum() - 1) * dto.getPageSize(); // 计算起始位置
        int end = start + dto.getPageSize() - 1; // 计算结束位置（下标需要 -1）
        String userMsgListKey = getUserMsgListKey(userId); // 获取用户消息列表的缓存键

        // 从 Redis 中获取消息文本 ID 列表
        List<Long> msgTextIdList = redisService.getCacheListByRange(userMsgListKey, start, end, Long.class);
        List<MessageTextVO> messageTextVOList = assembleMsgTextVOList(msgTextIdList); // 组装消息文本视图对象列表

        // 如果缓存中没有数据，则从数据库中查询并刷新缓存
        if (CollectionUtil.isEmpty(messageTextVOList)) {
            messageTextVOList = getMsgTextVOListByDB(dto, userId); // 从数据库中获取数据
            refreshCache(userId); // 刷新缓存
        }
        return messageTextVOList;
    }

    /**
     * 组装消息文本视图对象列表。
     *
     * @param msgTextIdList 消息文本 ID 列表
     * @return 消息文本视图对象列表
     */
    private List<MessageTextVO> assembleMsgTextVOList(List<Long> msgTextIdList) {
        if (CollectionUtil.isEmpty(msgTextIdList)) { // 如果消息文本 ID 列表为空
            return null;
        }

        // 拼接消息详情的缓存键
        List<String> detailKeyList = new ArrayList<>();
        for (Long textId : msgTextIdList) {
            detailKeyList.add(getMsgDetailKey(textId)); // 拼接缓存键并存入列表
        }

        // 从 Redis 中批量获取消息详情
        List<MessageTextVO> messageTextVOList = redisService.multiGet(detailKeyList, MessageTextVO.class);
        CollUtil.removeNull(messageTextVOList); // 移除空值

        // 如果缓存中的数据不完整，则返回 null
        if (CollectionUtil.isEmpty(messageTextVOList) || messageTextVOList.size() != msgTextIdList.size()) {
            return null;
        }
        return messageTextVOList;
    }

    /**
     * 从数据库中获取用户消息列表。
     *
     * @param dto    分页查询条件
     * @param userId 用户 ID
     * @return 用户消息列表
     */
    private List<MessageTextVO> getMsgTextVOListByDB(PageQueryDTO dto, Long userId) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize()); // 使用分页插件
        return messageTextMapper.selectUserMsgList(userId); // 查询用户消息列表
    }
}